home *** CD-ROM | disk | FTP | other *** search
- /*
- C* -- Parser Part II (declarations)
-
- Source: dcl.c
- Started: October 21, 1985
- Version:
- March 4, 1987;
- February 25, 1989: New Sherlock macros added.
-
- PUBLIC DOMAIN SOFTWARE
-
- The CSTAR program was placed in the public domain on June 15, 1991,
- by its author and sole owner,
-
- Edward K. Ream
- 1617 Monroe Street
- Madison, WI 53711
- (608) 257-0802
-
- CSTAR may be used for any commercial or non-commercial purpose.
-
- See cstar.h or cstar.c for a DISCLAIMER OF WARRANTIES.
- */
- #include "cstar.h"
-
- /*
- WARNING: according to the C Journal, Winter 1987, p.58, const and
- volatile don't stick to structure tags. Our copy of the draft
- standard is silent on this arcane point. Use #define SC_STICKY 0
- to implement them that way, and use 1 to implement them as pure
- type adjectives which behave cumulatively.
-
- WARNING: pd_taeq and pd_teq: it is not clear whether structures
- having the same tag (and which are therefore identical in all respects
- except outer const and volatile) but differing as to outer
- const or volatile should be regarded as being of the same type or as
- of different types. At present, as with const and nonconst int,
- they are regarded as if they are the same type, for most purposes.
- */
- extern int reg_size[];
-
- /*
- Externally visible routines:
- */
- void pd_tcopy (struct type_node *s, struct type_node *d);
- bool pd_teq (struct type_node *t1, struct type_node *t2);
- bool pd_t1eq (struct type_node *t1, struct type_node *t2);
- bool pd_taeq (struct type_node *t1, struct type_node *t2);
- void reg_check (struct type_node *type, int regtype, char *symbol);
- unsigned long m_size (int m);
- bool pd_is1func (struct type_node *t);
- void pd_orphan (struct type_node *t);
- struct type_node *
- pd_cast (void);
- struct type_node *
- pd_stmt (int kind, int plural, struct type_node **head_x);
-
-
- /*
- Internal routines:
- */
- static struct type_node *
- pd_head (int kind, int * sclass);
- static struct type_node *
- pd_tail (int kind, struct type_node *head_type,
- char ** dsymbol, int * regtype, int headclass);
- static struct type_node *
- pd_t1 (int kind, struct type_node * head_type,
- char ** dsymbol, int * regtype, int headclass);
- static int
- pd_post (register struct type_node *t);
- static struct type_node *
- pd_p1 (register struct type_node *t, register int mods);
- static struct st_node *
- pd_var (int sclass, struct type_node *type, char * symbol);
- static char * pd_name (void);
- static void pd_iniz (struct st_node *id);
- static struct iblock *
- pd_par (register struct type_node *t, unsigned long size);
-
-
- /*
- NOTE about const and volatile
-
- Handling of CONST_MOD and VOLATILE_MOD is peculiar. See this
- entire note.
-
- const and volatile are peculiar entities, not really storage classes,
- and not really types. Like static, volatile will typically be
- a statement about the properties of a location. However,
- syntactically and logically to a certain extent, it is treated
- as a type. One does not distinguish pointer to static int from
- pointer to some other int, but one does distinguish pointer
- to volatile int from pointer to int from volatile pointer to int.
- (Actually, one might want to distinguish pointer to auto int
- from pointer to static int, and disallow returning the former it
- from a function, but let that slide.)
-
- In addition, const and volatile have implications for expression
- checking and code generation and act in that context rather like
- types, in they disallow certain operations in rather the
- same manner that inappropriate types would disallow them. With
- the sole exception of address-of a register, storage classes
- don't do that.
-
- Furthermore, const and volatile (?) propagate within aggregates,
- so that if an array is const, so are its elements. This is also
- implicitly true of all other storage classes, but it has no
- consequences to speak of, because those storage classes attach
- to the declared object rather than to its type specification.
-
- Because of the other-worldly syntax of declarations, which
- can't be blamed on the standards committee, a number of
- bizarre facts need to be noted:
-
- 1. a declaration like
- const int ** const * x;
- is possible, as is the corresponding cast. Blame the
- original syntax for suggesting this form, and the
- committee for accepting the suggestion.
-
- 2. in the declaration
- const static unsigned int *x;
- register describes the location where the pointer-to-integer
- x is stored, but const (implicitly) describes the location
- which x points to (i.e., it is to be treated like ROM),
- while unsigned describes how said location (be it static,
- ROM, or both) is to be regarded when used as an arithmetic
- entity. That is, one must remember which of the twenty-odd
- possible descriptors gets attached to the pointer, and
- which to the item pointed to, in such declarations.
-
- 3. in full C, the useless declaration
- const register x;
- is syntactically possible. Its uselessness stems from
- the lack of any means to specify, either in the C code,
- or through the linker, which particular register is
- intended.
-
- 4. in the declaration
- const a[5];
- the const attribute attaches both to a, regarded as
- "the array" and to *(a+3), the latter being an array
- element, since the attribute propagates to the elements
- of an aggregate.
- In
- const *a;
- the const attribute attaches to *(a+3), but not to
- "the pointer" a.
- Finally, in the formal
- const a[];
- your guess is as good as ours. Ours is to treat it
- exactly as if
- const *a;
- had been written.
-
- Within the C-Star compiler, there are a number of complex
- implications.
-
- 1. Normal storage classes get attached directly to
- the symbol table entry, since they have nothing
- to do with its type, although some classes are not
- allowed for some types.
-
- 2. Normal type specifiers are divided into two classes,
- roughly types and modifiers. The mutually exclusive
- set int, pointer, array, struct, union, float are
- treated as type, and entered as the primary node type.
- The rest, including char, are treated as modifiers,
- some of which may disallow others.
-
- 3. const and volatile are treated as special modifiers
- (SC_MODS). Their storage-class-like properties
- require them to propagate, however, and the kludge
- which handles this is located partly in pd_stmt
- and partly in pd_alloc.
-
- const and volatile are handled in pd_stmt, pd_head, pd_tail,
- and pd_alloc, and in some non-obvious ways that must not be
- tampered with lightly. (other analogous modifying declarators
- are handled fully by pd_head.) pd_head parses them in the
- obvious way. pd_tail parses them after the pointer-to
- asterisk, and attaches them to the proper pointer-to nodes,
- according to an extension of the usual inside-out syntax.
- pd_stmt propagates them from STRUCT_TYPE and UNION_TYPE heads
- to SELEMENT and UELEMENT nodes (only). This simplifies pd_alloc,
- which does the remaining propagation.
- */
-
- /* ---------- VISIBLE FUNCTIONS ----------- */
- /*
- Copy one existing type_node into another existing type_node.
- This is a kludge to allow for the redeclaration of formals.
- */
- void
- pd_tcopy(register struct type_node *s, struct type_node *d)
- {
- register int i;
-
- TRACEPB("pd_tcopy", printf("(%p, %p)\n", s, d));
-
- if (s == NULL || d == NULL) {
- RETURN_VOID("pd_tcopy");
- }
- i = sizeof(struct type_node)/sizeof(int);
- while (i--) {
- *((int *)d)++ = *((int *)s)++;
- }
-
- TICKX("pd_tcopy");
- }
-
- /*
- Check for fairly rigorous type equality.
- SC_MODS (e.g. CONST_MOD) are not checked here; the appropriate
- branch of setype checks those (e.g. assignments check CONST_MOD).
- */
- bool
- pd_teq(struct type_node *t1, struct type_node *t2)
- {
- bool result;
-
- TRACEPB("pd_teq",
- printf("(%p, %p)\n", t1, t2);
- pr_type(t1); pr_type(t2));
-
- while (t1 && t2) {
- if (t1 == t2) {
- RETURN_BOOL("pd_teq", TRUE);
- }
- if ( t1 -> t_typtok != t2 -> t_typtok) {
- RETURN_BOOL("pd_teq", FALSE);
- }
-
- switch (t1 -> t_typtok) {
- case STRUCT_TYPE:
- case UNION_TYPE:
- /* structs same if t1 == t2 or if same tag */
- if(t1 -> t_parent && t1 -> t_parent == t2 -> t_parent){
- RETURN_BOOL("pd_teq", TRUE);
- }
- else {
- RETURN_BOOL("pd_teq", FALSE);
- }
-
- case POINTER_TYPE:
- /* pointer to void matches pointer to anything else */
- t1 = t1 -> t_link;
- t2 = t2 -> t_link;
- if (t1 && t2 && (t1 -> t_typtok == VOID_TYPE ||
- t2 -> t_typtok == VOID_TYPE)) {
- RETURN_BOOL("pd_teq", TRUE);
- }
- break;
-
- case ARRAY_TYPE:
- if (t1 -> t_tdim != t2 -> t_tdim ||
- t1 -> t_tsize != t2 -> t_tsize) {
- RETURN_BOOL("pd_teq", FALSE);
- }
- goto linkit;
-
- case INT_TYPE:
- if ( (t1->t_mclass & ~SC_MODS) !=
- (t2->t_mclass & ~SC_MODS) ) {
- RETURN_BOOL("pd_teq", FALSE);
- }
- /* FALLTHROUGH */
-
- linkit:
- default:
- t1 = t1 -> t_link;
- t2 = t2 -> t_link;
- }
- }
- RETURN_BOOL("pd_teq", t1 == t2);
- }
-
- /*
- Check for slightly less rigorous type equality; array top-level
- need not match.
- */
- bool
- pd_t1eq(register struct type_node *t1, register struct type_node *t2)
- {
- TRACEPB("pd_t1eq",
- printf("(%p, %p)\n", t1, t2);
- pr_type(t1); pr_type(t2));
-
- if (t1 && t1 -> t_typtok == ARRAY_TYPE &&
- t2 && t2 -> t_typtok == ARRAY_TYPE) {
- RETURN_BOOL("pd_t1eq", pd_teq(t1 -> t_link, t2 -> t_link));
- }
- else {
- RETURN_BOOL("pd_t1eq", pd_teq(t1, t2));
- }
- }
-
- /*
- As pd_teq, except that POINTER_TYPE matches any ARRAY_TYPE at each
- [linear-] tree level.
-
- Arrays of different dimensionality still cause a mismatch.
- This is based on the notion that if someone writes array of 10
- and pointer to same, that is what one wants; pointer to pointer
- or maybe pointer to void would more usually be written.
- */
- bool
- pd_taeq(register struct type_node *t1, register struct type_node *t2)
- {
- TRACEPB("pd_taeq",
- printf("(%p, %p)\n", t1, t2);
- pr_type(t1); pr_type(t2));
-
- while (t1 && t2) {
- TRACE("pd_taeq", printf("pd_taeq loop: %p, %p\n", t1, t2));
- if (t1 == t2) {
- RETURN_BOOL("pd_taeq", TRUE);
- }
- if (t1 -> t_typtok != t2 -> t_typtok) {
- if ( (t1 -> t_typtok == POINTER_TYPE &&
- t2 -> t_typtok == ARRAY_TYPE) ||
- (t2 -> t_typtok == POINTER_TYPE &&
- t1 -> t_typtok == ARRAY_TYPE) ) {
- /* allow mixed case */
- t1 = t1 -> t_link;
- t2 = t2 -> t_link;
- TRACEP("pd_taeq", printf("mixed p/a\n"));
- continue;
- }
- else {
- TRACEP("pd_taeq", printf("typtok mismatch\n"));
- RETURN_BOOL("pd_taeq", FALSE);
- }
- }
-
- /* in the mixed pointer/array case, it never gets here */
- switch (t1 -> t_typtok) {
- case STRUCT_TYPE:
- case UNION_TYPE:
- /* structs same if t1 == t2 or if same tag */
- if(t1 -> t_parent && t1 -> t_parent == t2 -> t_parent){
- RETURN_BOOL("pd_taeq", TRUE);
- }
- else {
- RETURN_BOOL("pd_taeq", FALSE);
- }
-
- case POINTER_TYPE:
- /* pointer to void matches pointer to anything else */
- t1 = t1 -> t_link;
- t2 = t2 -> t_link;
- if (t1 && t2 && (t1 -> t_typtok == VOID_TYPE ||
- t2 -> t_typtok == VOID_TYPE)) {
- RETURN_BOOL("pd_taeq", TRUE);
- }
- break;
-
- case ARRAY_TYPE:
- if (t1 -> t_tdim != t2 -> t_tdim ||
- t1 -> t_tsize != t2 -> t_tsize) {
- RETURN_BOOL("pd_taeq", FALSE);
- }
- goto tanext;
-
- case INT_TYPE:
- if ( (t1->t_mclass & ~SC_MODS) !=
- (t2->t_mclass & ~SC_MODS) ) {
- TRACE("pd_taeq", printf("pd_taeq mclass FALSE: %d, %d\n",
- t1 -> t_mclass & ~SC_MODS,
- t2 -> t_mclass & ~SC_MODS));
- RETURN_BOOL("pd_taeq", FALSE);
- }
- /* FALLTHROUGH */
-
- tanext:
- default:
- t1 = t1 -> t_link;
- t2 = t2 -> t_link;
- }
- }
- RETURN_BOOL("pd_taeq", (t1 == t2));
- }
-
- /*
- Check the type of a register, for aggregates, wrong length, etc.
- Do t_error() if it is bad; but do not attempt any patch or fix.
- Reg_type must not be zero.
- */
- void
- reg_check(struct type_node *type, int regtype, char *symbol)
- {
- TRACEPB("reg_check", printf("(%p, %d, %s)\n", type, regtype, symbol));
-
- switch(type -> t_typtok) {
- case INT_TYPE:
- case POINTER_TYPE:
- if ((unsigned long)(unsigned)
- reg_size[regtype] != type -> t_tsize) {
- t_2error("type is of inappropriate length for: ",
- symbol);
- }
- break;
- default:
- t_2error("register not pointer or integer: ",symbol);
- break;
- }
-
- TICKX("reg_check");
- }
-
- /*
- Return the size of an mclass
- */
- unsigned long
- m_size(int m)
- {
- TICK("m_size");
-
- if (m & LONG_MOD) {
- return (long)LONG_SIZE;
- }
- else if (m & CHAR_MOD) {
- return (long)CHAR_SIZE;
- }
- else if (m & SHORT_MOD) {
- return (long)SHORT_SIZE;
- }
- else {
- return (long)INT_SIZE;
- }
- }
-
- /*
- Test a DELEMENT type_node to see if it is a declaration of exactly one
- function.
- */
- bool
- pd_is1func(struct type_node *t)
- {
- TRACEPB("pd_is1func", printf("(%p)\n", t));
-
- if (t -> t_list != NULL || t -> t_link == NULL) {
- RETURN_BOOL("pd_is1func", FALSE);
- }
- if (t -> t_link -> t_typtok != FUNCTION_TYPE) {
- RETURN_BOOL("pd_is1func", FALSE);
- }
- RETURN_BOOL("pd_is1func", TRUE);
- }
-
- /*
- Given a DELEMENT, go through the list and null out all the
- parent nodes. This is for removing names of formals from a function
- argument list once the names go out of scope. It is meant
- to ensure that there aren't any dangling pointers left around.
- */
- void
- pd_orphan(register struct type_node *t)
- {
- TRACEPB("pd_orphan", printf("(%p)\n", t));
-
- while (t != NULL) {
- if (t -> t_typtok != DELEMENT_TYPE) {
- t_error("pd_orphan: internal: not a D_ELEMENT");
- break;
- }
- t -> t_parent = NULL;
- t = t -> t_list;
- }
-
- TICKX("pd_orphan");
- }
-
- /*
- Handle the innards of a cast. Return NULL if not cast.
- The decision as to whether "not a cast" is an error
- IS TO BE MADE BY THE CALLER.
-
- The opening parenthesis has already been read.
- This form is also called by do_sizeof()
- */
- struct type_node *
- pd_cast(void)
- {
- register struct type_node * t;
- register struct st_node * id;
- int class;
-
- TICKB("pd_cast");
-
- if (is_kdecl(t_type) ||
- ( t_type == ID_TOK && (id = ast_lookup(t_symbol)) != NULL &&
- id -> st_sclass == TYPEDEF_CLASS) ) {
- /* note that pd_head ALWAYS returns something */
- t = pd_head(CAST_TYPE, &class);
- t = pd_tail(CAST_TYPE, t, NULL, NULL, NULL_CLASS);
- RETURN_PTR("pd_cast", t);
- }
- RETURN_PTR("pd_cast", NULL);
- }
-
-
- /*
- Parse a list of declarations.
-
- Each declaration consists of:
- exactly one pd_head
- followed by:
- repeated pd_tails separated by commas
- and terminating
- with a comma, if there is more
- with a type keyword, if formal decls follow
- with a left brace, if function defn and no decls
- with a non-comma, otherwise
-
- a function definition causes a fatal error if it is not
- in FILE_SCOPE.
-
- kind: NULL_TYPE: build no list
- UELEMENT_TYPE: build a union element list
- SELEMENT_TYPE: build a structure element list
- DELEMENT_TYPE: build a declaration list
-
- plural:
- TRUE: parse a series of decls into one list, taking up
- the last semicolon. it is assumed that
- the routine is called on a proper decl head.
- the storage class defaults to something
- suitable to the scope.
-
- FALSE: parse only as long as more commas are encountered, and
- leave the non-comma token. a proper decl head
- is not required; the first item may be an
- identifier, which will be defaulted to an
- int of storage class suitable to the scope
-
- head_x:
-
- NULL: nothing happens
-
- ADDRESS: address of head-type node is returned here.
- this is senseless if plural is enabled.
-
- return: kind == NULL_TYPE:
- NULL
- kind != NULL_TYPE:
- a list of typenodes of type kind, threaded
- via t_list, with each of these nodes
- attached to a typenode string threaded via
- t_link. see above for the sensible values
- of kind. NOTE: you only get the chain of
- element nodes, not the enclosing STRUCT,
- UNION, or DECL. see list above.
-
- IN THE EVENT OF A DUPLICATE DECLARATION, SOMETHING REFLECTING THE
- OLD TYPE, NOT THE CURRENT PARSE, IS HOOKED INTO THE LIST!!!
-
- This keeps symbol table nodes and parent nodes linked properly,
- but it may lead to amusing structure definitions.
-
- It also makes it easier to handle the redeclaration of formals,
- which is really why it was done.
-
- In this event, t_error is raised, so no code should be generated
- anyhow.
- */
- struct type_node *
- pd_stmt(int kind, int plural, struct type_node **head_x)
- {
- register struct type_node *d_type, *type, *head_type;
- int head_class;
- struct st_node *id;
- struct type_node root_node;
- register struct type_node *ltail, *lp;
-
- char *symbol;
- int regtype;
-
- /*
- First parse the head.
- See notes on pd_head to know what a head is!
- */
-
- TRACEPB("pd_stmt", printf("(%d, %d, %p)\n", kind, plural, head_x));
-
- root_node.t_list = NULL;
- ltail = &root_node;
-
- for (;;) {
- head_type = pd_head(kind, &head_class);
-
- /* parse a list of tails, until a non-comma */
- for(;;) {
- symbol = NULL;
- id = NULL;
- d_type = type =
- pd_tail(kind, head_type,
- &symbol, ®type, head_class);
-
- if (kind) {
- lp = new_tnode();
- lp -> t_typtok = kind;
- lp -> t_link = type;
-
- ltail -> t_list = lp;
- ltail = lp;
-
- switch(kind) {
- case UELEMENT_TYPE:
- d_type = lp;
- if ((type -> t_typtok == STRUCT_TYPE ||
- type -> t_typtok == UNION_TYPE) &&
- type -> t_list == NULL) {
- t_error("undefined struct/union");
- }
- break;
-
- case SELEMENT_TYPE:
- d_type = lp; /* so that variable, as
- entered in symbol table,
- shows up as element type */
- if ((type -> t_typtok == STRUCT_TYPE ||
- type -> t_typtok == UNION_TYPE) &&
- type -> t_list == NULL) {
- t_error("undefined struct/union");
- }
- break;
-
- case DELEMENT_TYPE:
- break;
-
- default:
- t_error("pd_stmt: shouldn't happen");
- }
- }
- /* end of the element */
-
- /*
- note: certain declarations of formals are
- disallowed by pd_var and need not concern
- us here.
- */
- if (symbol != NULL) {
- /* then something is declared */
- if (regtype) {
- reg_check(d_type, regtype, symbol);
- switch(head_class) {
- case REGISTER_CLASS:
- case AUTO_CLASS:
- id = pd_var(REGISTER_CLASS,
- d_type, symbol);
- id -> st_misc |= regtype;
- #ifdef SCRATCH
- if (regtype && reg_idx(regtype) <= SCRATCH) {
- #else
- if (regtype && reg_idx(regtype) == 0) {
- #endif
- t_2warning("register may be clobbered by function calls: ", arp_tab[regtype]);
- t_warning("that includes implicit function calls such as lmul");
- }
- break;
- default:
- id = pd_var(head_class, d_type, symbol);
- t_error("inappropriate use of register name keyword");
- }
- }
- else {
- id = pd_var(head_class, d_type, symbol);
- }
- d_type = type = id -> st_type;
- if (kind) {
- TRACEP("pd_stmt",
- printf("assign parent %p\n", id));
- lp -> t_parent = id;
- }
- }
- else if (head_type -> t_typtok != STRUCT_TYPE &&
- head_type -> t_typtok != UNION_TYPE) {
- t_warning("empty declaration");
- }
-
- /* check for initializer */
- if (kind == DELEMENT_TYPE && t_type == ASSN_TOK) {
- get_token();
- pd_iniz(id);
- }
-
- /* Is there another element? */
- if (t_type == COMMA_TOK) {
- get_token();
- }
- else {
- break;
- }
-
- } /* end tails loop */
-
- /* check for end of declaration */
- if (!plural) {
- break; /* out of statement-list loop */
- }
- if (t_type == SEMICOLON_TOK) {
- get_token();
- }
- else {
- need(SEMICOLON_TOK);
- if (is_kdecl(t_type) || t_type == LCURLY_TOK) {
- if (type != NULL &&
- type -> t_typtok == FUNCTION_TYPE) {
- t_warning("check brace structure");
- fatal("function definition in code");
- }
- }
- }
- /* now continue along if it's another type keyword */
- if (is_kdecl(t_type)) {
- continue;
- }
- else if (t_type == ID_TOK) {
- id = ast_lookup(t_symbol);
- if (id == NULL) {
- break;
- }
- else if (id -> st_sclass == TYPEDEF_CLASS) {
- continue;
- }
- else {
- break;
- }
- }
- else {
- break;
- }
- }
-
- /* Drop root node. */
- TRACEP("pd_stmt",
- printf("return type %p:\n",root_node.t_list);
- pr_type(root_node.t_list); printf("\n");
- );
-
- if (head_x) {
- #ifdef DEBUG
- if (plural) {
- t_error("pd_stmt: internal: senseless use of head_x");
- }
- #endif /* DEBUG */
- *head_x = head_type;
- }
- RETURN_PTR("pd_stmt", (root_node.t_list));
- }
-
- /*
- Parse the head of a declaration/function definition.
- Also see the notes under decl.
- Produce a type tree, and a storage-class word.
-
- A head contains:
- An optional sc-specifier
- and then
- Optional modifiers from the K&R list
- and then
- An optional noun, which may be
- A typedef tag
- or else
- A noun from the K&R list (e.g. int)
- or else struct or union followed by:
- either a structure tag
- or a struct/union definition (in braces)
- or both
-
-
- A head does not contain:
- Parentheses
- Asterisks
- Brackets
- Identifiers except for typedef tags
- or anything else, so it is deemed to end when such is found
-
- The node tree returned is supposed to always have a base
- type at the end of the typelink-string, that is, a noun keyword or
- a structure tag.
-
- The sequence:
- typedef unsigned tag;
- tag char xyz;
- shall lead to an error, the gist of which is that xyz cannot
- be both a char and an int. The distinction made herein
- between modifiers and nouns is muddled in the standard;
- although it seems not, it could be that it "really" is that
- allowed and disallowed keyword combinations are described
- by an arbitrary matrix.
-
- Every typelink-string must eventually end with a node
- whose t_typtok is one of:
- INT_TYPE
- STRUCT_TYPE
- UNION_TYPE
- VOID_TYPE
-
- and, in particular, is not one of:
- ARRAY_TYPE
- FUNCTION_TYPE
- POINTER_TYPE
- SELEMENT_TYPE
- UELEMENT_TYPE
-
- The STRUCT_TYPE and UNION_TYPE nodes have a second pointer
- which is the list of element nodes.
-
- kind: CAST_TYPE: declaration is inside a cast
- SELEMENT_TYPE: declaration is inside a struct
- UELEMENT_TYPE: declaration is inside a union
-
- sclass: address-of the storage class, which
- is no longer part of the type node
-
- return: a type_node which reflects the contents
- of the "header"
- SOMETHING IS ALWAYS RETURNED; RESULT IS NEVER
- EVER NULL. the default is a 2-byte int.
- */
- static struct type_node *
- pd_head(int kind, int * sclass)
- {
- register struct st_node *id, *id1;
- register struct type_node *t, *t1;
- register int sc_count, m;
- int s_f, u_f;
- long ssize;
- char *symbol;
-
- /* Set up as a default to auto int. */
-
- TRACEPB("pd_head", printf("(%d, %p)\n", kind, sclass));
-
- t = new_tnode();
- TRACEP("pd_head", printf("new_tnode %p\n", t));
-
- switch(scope.s_scope) {
- case PROTO_SCOPE:
- case FNDEF_SCOPE:
- *sclass = FORMAL_CLASS;
- break;
-
- case BLOCK_SCOPE:
- *sclass = AUTO_CLASS;
- break;
-
- case FILE_SCOPE:
- *sclass = GLOBAL_CLASS;
- break;
- default:
- fatal("pd_head: internal: unknown scope");
- }
-
- /* Storage-class specifiers. */
- sc_count = 0;
- for(;;) {
- switch(t_type) {
-
- case K_TYPEDEF:
- switch(scope.s_scope) {
- case PROTO_SCOPE:
- case FNDEF_SCOPE:
- t_error("typedef keyword in formal");
- break;
- default:
- *sclass = TYPEDEF_CLASS;
- }
- sc_count++;
- get_token();
- continue;
-
- case K_EXTERN:
- switch(scope.s_scope) {
- case PROTO_SCOPE:
- case FNDEF_SCOPE:
- t_error("extern declaration of formal");
- break;
- default:
- *sclass = EXTERN_CLASS;
- }
- sc_count++;
- get_token();
- continue;
-
- case K_AUTO:
- if (scope.s_scope == BLOCK_SCOPE) {
- *sclass = AUTO_CLASS;
- }
- else {
- t_error("auto declaration--not a local variable");
- }
- sc_count++;
- get_token();
- continue;
-
- case K_REGISTER:
- TRACEP("pd_head", printf("K_REGISTER, scope %d\n",
- scope.s_scope));
- switch(scope.s_scope) {
- case PROTO_SCOPE:
- case FNDEF_SCOPE:
- *sclass = FORMREG_CLASS;
- break;
- case BLOCK_SCOPE:
- *sclass = REGISTER_CLASS;
- break;
- default:
- t_error("global declared as register type");
- }
- sc_count++;
- get_token();
- continue;
-
- case K_STATIC:
- switch(scope.s_scope) {
- case PROTO_SCOPE:
- case FNDEF_SCOPE:
- t_error("static declaration of formal");
- break;
- case BLOCK_SCOPE:
- *sclass = STATICL_CLASS;
- break;
- default:
- *sclass = STATICG_CLASS;
- break;
- }
- sc_count++;
- get_token();
- continue;
- }
- break;
- }
- if (sc_count > 1) {
- t_error("more than one sc-specifier in declaration");
- }
-
- if (sc_count) {
- switch (kind) {
- case CAST_TYPE:
- t_error("sc-specifier within cast");
-
- break;
- case UELEMENT_TYPE:
- case SELEMENT_TYPE:
- t_error("sc-specifier inside structure or union");
- }
- }
-
- /* Modifiers of the base type. */
- s_f = u_f = 0;
- for(;;) {
- TRACEP("pd_head", printf("modifier\n"));
- switch(t_type) {
-
- case K_CONST:
- t -> t_mclass |= CONST_MOD;
- get_token();
- continue;
-
- case K_VOLATILE:
- t -> t_mclass |= VOLATILE_MOD;
- get_token();
- continue;
-
- case K_UNSIGNED:
- u_f = 1;
- if (s_f) {
- t_error("signed unsigned??");
- }
- get_token();
- continue;
-
- case K_SIGNED:
- s_f = 1;
- if (u_f) {
- t_error("unsigned signed??");
- }
- get_token();
- continue;
-
- case K_CHAR:
- if (t -> t_mclass & (LONG_MOD | SHORT_MOD)) {
- t_error("long/short char??");
- }
- else {
- t -> t_mclass |= CHAR_MOD;
- t -> t_tsize = CHAR_SIZE;
- }
- get_token();
- continue;
-
- case K_SHORT:
- if (t -> t_mclass & (LONG_MOD | CHAR_MOD)) {
- t_error("long/char short??");
- }
- else {
- t -> t_mclass |= SHORT_MOD;
- t -> t_tsize = SHORT_SIZE;
- }
- get_token();
- continue;
-
- case K_LONG:
- if (t -> t_mclass & (SHORT_MOD | CHAR_MOD)) {
- t_error("char/short long??");
- }
- else {
- t -> t_mclass |= LONG_MOD;
- t -> t_tsize = LONG_SIZE;
- }
- get_token();
- continue;
-
- }
- break;
- }
- if (s_f) {
- t -> t_mclass &= ~UNSIGNED_MOD;
- }
- else if (u_f) {
- t -> t_mclass |= UNSIGNED_MOD;
- }
-
- /* Pick up the base type. */
- TRACEP("pd_head", printf("base type\n"));
- switch(t_type) {
- case K_INT:
- get_token();
- break;
-
- case K_VOID:
- t -> t_typtok = VOID_TYPE;
- t -> t_tsize = 0;
- if (t -> t_mclass & ARITH_MODS) {
- t_error("long, short, etc. do not apply to void");
- t -> t_mclass &= ~ARITH_MODS;
- }
- get_token();
- break;
-
- case K_UNION:
- case K_STRUCT:
- if (t_type == K_STRUCT) {
- kind = SELEMENT_TYPE;
- t -> t_typtok = STRUCT_TYPE;
- }
- else {
- kind = UELEMENT_TYPE;
- t -> t_typtok = UNION_TYPE;
- }
- t -> t_tsize = 0;
-
- if (t -> t_mclass & ARITH_MODS) {
- t_error("long, short, etc. do not apply to struct/union");
- t -> t_mclass &= ~ARITH_MODS;
- }
- get_token();
-
- /*
- Deal with tag if there is one
- */
-
- /*
- WARNING: this code cannot check for undefined tags.
- That must be done by some sort of post-pass, or
- else by the operators that use structure elements
- An undefined tag is one that doesn't have a t_list
- (list of elements) by the time it is used in code.
- */
- id = NULL; /* Signify that there is no tag. */
- symbol = NULL; /* Set up for possible later use. */
- if (t_type == ID_TOK) {
- /* Must be a tag. */
- symbol = str_salloc(t_symbol);
- id = ast_lookup(t_symbol);
- get_token();
-
- if (id == NULL) {
- /* a possibly vacuous entry */
- id = rst_enter(symbol, t, TAG_CLASS);
- }
- else if (id -> st_sclass != TAG_CLASS) {
- /*
- A symbol of this name exists. If
- it is not in the CURRENT scope,
- re-enter it. If it is in the current
- scope, then it is no good.
- */
- id = rst_lookup(symbol);
- if (id == NULL) {
- id = rst_enter(symbol, t, TAG_CLASS);
- }
- }
- else if (t_type == LCURLY_TOK) {
- /*
- Re-enter the symbol in the current scope
- if and only if a definition follows
- */
- id = rst_lookup(symbol);
- if (id == NULL) {
- t_2warning("definition hides earlier one: ", symbol);
- id = rst_enter(symbol, t, TAG_CLASS);
- }
- }
- /* id is not null any more, ever, at this point */
- /* however, id is not guaranteed to be valid yet */
-
- /* Now check the tag for certain kinds of validity. */
- if (id -> st_sclass != TAG_CLASS) {
- t_2error("not a tag: ", symbol);
- id = NULL;
- }
- else if (id -> st_type == NULL) {
- t_2error("internal: untyped tag: ", symbol);
- id -> st_type = t;
- }
- else if (id -> st_type -> t_typtok != t -> t_typtok) {
- t_2error("conflicting struct/union use of tag: ", symbol);
- TRACEP("pd_head1",
- pr_type(id -> st_type); printf("\n");
- pr_type(t); printf("\n"));
- id = NULL;
- }
- }
- /* id is null here, if no tag is in use */
-
- /* Perform a structure definition. */
- if (t_type == LCURLY_TOK) {
- if (kind == CAST_TYPE) {
- fatal("{ inside cast");
- }
-
- /* Process the structure list. */
- TRACEP("pd_head", printf("structure list\n"));
- need(LCURLY_TOK);
- t -> t_list = pd_stmt(kind, TRUE, NULL);
- if (t -> t_list == NULL) {
- t_error("empty structure definition");
- }
- t -> t_tsize = pd_alloc(t -> t_list,
- (kind == SELEMENT_TYPE)? 2 : 3);
- need(RCURLY_TOK);
- TRACEP("pd_head", printf("end structure list\n"));
-
- if (id != NULL && id -> st_type != t) {
- /* place the results of the definition */
- TRACEP("pd_head", printf("redefine tag\n"));
- if (id -> st_type -> t_list == NULL) {
- id -> st_type -> t_list = t -> t_list;
- id -> st_type -> t_tsize =
- t -> t_tsize;
- t = id -> st_type;
- }
- else {
- t_2error("redefinition of tag: ",symbol);
- }
- }
- #if SC_STICKY == 0
- /*
- remove SC_MODS from the tag
- pd_post has not been called at this level at
- this time, so no recursion is required;
- it would be impossible anyhow
- */
- if (t -> t_mclass && id) {
- t1 = t;
- t = node_dupl(
- (byte *) t, sizeof(struct type_node));
- t1 -> t_mclass &= ~SC_MODS;
- }
- TRACEP("pd_head", printf("detach tag from: ");
- pr_type(t));
- #endif
- }
- else {
- /* it's not a definition, so use what got looked
- up, if it was valid */
- if (id != NULL) {
- t -> t_list = id -> st_type -> t_list;
- t -> t_tsize = id -> st_type -> t_tsize;
- #if SC_STICKY != 0
- t -> t_mclass |= id -> st_type -> t_mclass;
- #endif
- }
- }
- /* attach tag name to structure node */
- t -> t_parent = id;
- break;
-
- case STAR_TOK:
- case LPAREN_TOK:
- /* Declarator may be imbedded. */
- break;
-
- case ID_TOK:
- /*
- Check to see whether ID is a typedef tag, or
- a variable or typedef identifier.
-
- Under error conditions we have some
- semantics-dependent syntax here. Maybe.
-
- We assume that if it's not typedef'd, then
- it's a function declarator.
- */
- id = ast_lookup(t_symbol);
- if (id != NULL && id -> st_sclass == TYPEDEF_CLASS) {
- if (t -> t_mclass & ARITH_MODS) {
- t_error("long, short, etc. do not apply to typedef tag");
- t -> t_mclass &= ~ARITH_MODS;
- }
- if (id -> st_type != NULL) {
- t = id -> st_type;
- }
- else {
- t_2error("pd_head: internal: typedef tag has NO TYPE: ", t_symbol);
- }
- get_token();
- }
- break;
-
- default:
- if (kind != CAST_TYPE) {
- t_error("variable declarator expected");
- TRACEP("pd_head", printf("token = %d\n", t_type));
- }
- }
- TRACEP("pd_head", printf("returns %p\n", t));
- #ifdef DEBUG
- if (t == NULL) {
- fatal("pd_head: internal: returns NULL");
- }
- #endif
- RETURN_PTR("pd_head", t);
- }
-
- /*
- Parse one declaration tail--that is, one collection of asterisks,
- parentheses, and brackets, possibly with an imbedded identifier.
- (This code handles casts, so the identifier is not always required.)
- Call t_error if an identifier that should be imbedded isn't,
- or in case of a duplicate, etc.
-
- Enter imbedded identifier into symbol table, and return the
- entry if an address for it is given.
-
- Parse grouping parentheses by recursive descent.
-
- Assumptions:
- The operator * is a prefix operator.
- The operators () and [] are postfix operators.
- The operator [25] is a case of [].
- The new-standard version of the arg list is not (yet) handled.
-
- kind:
- CAST_TYPE: declaration is inside a cast.
- SELEMENT_TYPE: declaration is inside a struct.
- UELEMENT_TYPE: declaration is inside a union.
-
- headclass:
- EXTERN_CLASS: etc.; includes classes denoted by
- keywords, and others
-
- Storage class to be attached to newly defined st_nodes.
-
- head_type:
- Whatever type the item is pointer-to, array-of, etc.;
- head_type is passed as NULL on descent!
-
- dsymbol:
- Address of a place to put a pointer to the symbol text,
- should one be found. caller should set contents of that
- address to NULL, so as to be able to tell.
- regtype:
- Address of a place to put the register subtype at the
- time dsymbol is set, if dsymbol is set.
-
- return:
- Pointer to a type_node.
-
- fndef_ok:
- flag indicating that an identifier has been seen.
- Thus, function definition is possible.
-
- fnoverrun:
- Flag indicating that a '(' starting a function has been seen.
- */
- static struct type_node *
- pd_tail (int kind, struct type_node * head_type,
- char ** dsymbol, int * regtype, int headclass)
- {
- register struct type_node *t;
-
- TRACEPB("pd_tail", printf("(%d, %p, %p, %p, %d)\n",
- kind, head_type, dsymbol, regtype, headclass));
-
- if (dsymbol != NULL) {
- *dsymbol = NULL;
- }
- t = pd_t1(kind, head_type, dsymbol, regtype, headclass);
- if (t == NULL) {
- fatal("pd_tail: internal: returns NULL");
- }
- (void) pd_post(t);
- RETURN_PTR("pd_tail", t);
- }
-
- static struct type_node *
- pd_t1( int kind, struct type_node * head_type,
- char ** dsymbol, int * regtype, int headclass)
- {
- register struct st_node *id;
- register struct node *p;
- int firstary;
- struct type_node root_node;
- struct type_node *star_node, *star_tail;
- register struct type_node *f_p, *t, *tail;
-
- bool fndef_ok, fnoverrun;
-
- TRACEPB("pd_t1", printf("(%d, %p, %p, %p, %d)\n",
- kind, head_type, dsymbol, regtype, headclass));
-
- TRACEP("pd_t1",
- printf("head_type %p; current t_type %d\n",
- head_type, t_type));
-
- /*
- NOTE:
- root_node is a vacuous item which is always
- on the modifying-declarator list, so that we need
- not replicate list-setup code all over the place
- */
- root_node.t_link = NULL;
- tail = &root_node;
-
- star_node = NULL;
-
- id = NULL;
- fnoverrun = 0;
- firstary = TRUE;
-
- /* Note again: ONE tail */
-
- /*
- First count up asterisks--pointer to.
- This is PRIOR TO encountering the identifier.
- Stars get prepended.
- */
- if (t_type == STAR_TOK) {
- /* first prepending */
- t = new_tnode();
- t -> t_typtok = POINTER_TYPE;
- t -> t_tsize = POINTER_SIZE;
- star_node = star_tail = t;
-
- for(get_token(); ; get_token()) {
- switch(t_type) {
- case STAR_TOK:
- /* subsequent prependings */
- t = new_tnode();
- t -> t_typtok = POINTER_TYPE;
- t -> t_tsize = POINTER_SIZE;
- t -> t_link = star_node;
- star_node = t;
- continue;
- case K_CONST:
- t -> t_mclass |= CONST_MOD;
- continue;
- case K_VOLATILE:
- t -> t_mclass |= VOLATILE_MOD;
- continue;
- }
- break;
- }
- }
-
- /* There can now be no more stars at this paren level. */
-
- /*
- Left parenthesis could be grouping parenthesis or it could
- be function-decl parenthesis. Handle either case.
-
- If it is a function parenthesis, there can be no
- more left-parentheses for grouping, since the
- identifier or the missing identifier must be
- inside the innermost pair of grouping parentheses.
-
- Do the core, containing the (possibly implicit) identifier.
- A function () may be taken up as well.
- */
- if(t_type == LPAREN_TOK) {
- /*
- Since we have not seen an identifier yet, this branch
- can not lead to a function definition.
- */
- fndef_ok = FALSE;
- get_token();
- if (t_type == RPAREN_TOK) {
- /*
- Eventually, test for type declarator.
- We are in a cast for a function.
- */
- fnoverrun = TRUE;
- }
- else {
- /*
- The initial '(' was a grouping parenthesis.
- Parse the rest of the core recursively.
- */
- t = pd_t1(kind, NULL, dsymbol, regtype, headclass);
- if (t != NULL) {
- /* append core item */
- tail -> t_link = t;
- tail = t;
-
- /* reset tail */
- while (tail -> t_link) {
- tail = tail -> t_link;
- }
- }
- need(RPAREN_TOK);
- }
- }
- else if (t_type == ID_TOK) {
- /*
- Now that we have seen an identifier, it is possible
- for a function definition to appear.
- */
- fndef_ok = TRUE;
- if (kind == CAST_TYPE) {
- t_warning("identifier within cast ignored");
- }
- else {
- if (dsymbol != NULL) {
- *dsymbol = str_salloc(t_symbol);
- *regtype = t_subtype;
- if (is_aregw(t_subtype)) {
- t_2help(t_symbol, " has bizarre properties");
- }
- }
- }
- get_token();
- }
- else if (kind != CAST_TYPE &&
- head_type -> t_typtok != STRUCT_TYPE &&
- head_type -> t_typtok != UNION_TYPE) {
- fndef_ok = FALSE;
- t_error("missing object name in declaration");
- }
-
- /*
- GREAT DIVIDE.
-
- At this point, the core has been passed.
- We are ready to process function params or arrays.
- fnoverrun is a "virtual left paren" flag.
- */
- while (t_type == LPAREN_TOK || fnoverrun) {
- /*
- Append a function-returning node.
- With the new standard, these will have type lists,
- just like struct/union.
- */
- t = new_tnode();
- t -> t_typtok = FUNCTION_TYPE;
- t -> t_tsize = 0L;
- tail -> t_link = t;
- tail = t; /* t is never null */
-
- /* Take up left paren if it hasn't already been gobbled. */
- if (!fnoverrun) {
- get_token();
- }
- fnoverrun = FALSE;
-
- /* Process an argument list if there is one. */
- if (t_type == ID_TOK && fndef_ok) {
- if (scope.s_scope != FILE_SCOPE && t_type == ID_TOK) {
- fatal("function definition in non-external context");
- }
- scope.s_scope = FNDEF_SCOPE;
- f_p = t;
- /*
- Do an old-style K&R type arg list.
- This is roughly an abbreviated pd_stmt.
-
- WARNING:
- This will have to change in the new standard.
- */
- for(;;) {
- if (id = rst_lookup(t_symbol)) {
- t_2error("duplicate formal parameter: ",
- t_symbol);
- }
- else {
- f_p -> t_list = new_tnode();
- f_p = f_p -> t_list;
- f_p -> t_typtok = DELEMENT_TYPE;
- f_p -> t_link = new_tnode();
- id = rst_enter(t_symbol,
- f_p -> t_link, FORMAL_CLASS);
- f_p -> t_parent = id;
- }
-
- get_token();
- if (t_type != COMMA_TOK) {
- break;
- }
- get_token();
- if (t_type != ID_TOK) {
- t_error("missing formal parameter");
- break;
- }
- }
- scope.s_scope = FILE_SCOPE;
- }
- need(RPAREN_TOK);
- fndef_ok = FALSE;
- }
- /* at this point, we have processed leading *, the core, and
- any function-returning which are present at this level */
-
- while (t_type == LBRACK_TOK) {
- /* append array node */
- t = new_tnode();
- t -> t_typtok = ARRAY_TYPE;
- tail -> t_link = t;
- tail = t;
-
- /* eat the [ */
- get_token();
- TRACEP("pd_t1", printf("after [: t_type = %d\n",
- t_type));
-
- /* take the expression if there is one */
- switch(t_type) {
- case RCURLY_TOK:
- case LCURLY_TOK:
- case SEMICOLON_TOK:
- case EOF_TOK:
- case EOP_TOK:
- /* bad outcome */
- break;
-
- case RBRACK_TOK:
- if (firstary) {
- switch(headclass) {
- case FORMAL_CLASS:
- case FORMREG_CLASS:
- /* formal array of indefinite dim */
- t -> t_typtok = POINTER_TYPE;
- t -> t_tsize = POINTER_SIZE;
- break;
-
- case EXTERN_CLASS:
- /* external array of indefinite dim */
- break;
- default:
- /* allow pointer to / function rtng
- array of indefinite dimension */
- if (tail == &root_node) {
- t_error("missing array dimension");
- }
- }
- }
- else {
- t_error("missing array dimension");
- }
- break;
-
- default:
- if (is_key(t_type)) {
- break;
- }
- if (kind == CAST_TYPE) {
- p = pe_expr1(TRUE);
- }
- else {
- /* WARNING: used to be expr(TRUE); */
- p = pe_expr();
- }
- if (!pe_number(p)) {
- t_error("array dimension must be a constant");
- }
- else {
- t_value = p -> n_const;
-
- }
- TRACEP("pd_t1", printf("dimension %ld\n",
- t_value));
- if (t_value >= 0) {
- t -> t_tdim = t_value;
- }
- else {
- t_error("negative array dimension");
- }
- break;
-
- }
- need(RBRACK_TOK);
- firstary = FALSE;
- }
- /* at this point, array dimensions at this level have been done */
-
- if (t_type == LPAREN_TOK) {
- t_error("unexpected (");
- }
-
- /* append stars, which may carry their consts and volatiles */
- if (star_node) {
- tail -> t_link = star_node;
- tail = star_tail;
- }
-
- /* append head_type node */
- tail -> t_link = head_type;
-
- /* drop root_node. */
-
- RETURN_PTR("pd_t1", (root_node.t_link));
- }
-
- /* ------------- INVISIBLE FUNCTIONS ------------ */
-
-
- /*
- Go over the type (list of type_nodes) t1 and accomplish the following:
- assign array sizes
- complain about bad combinations, e.g. functions returning aggr.
- propagate const and volatile backwards across array-of
- and WARNING [forwards across structures]
- All of these involves interactions between two or more list elements,
- and the structure of this function reflects the fact that it does
- nothing if the list contains zero or one elements.
-
- CAUTION: it is assumed that t_mclass of non-int items only has
- SC_MODS raised. If this becomes untrue, it will be necessary to
- do more masking.
- */
- static int
- pd_post(register struct type_node *t)
- {
- register struct type_node *t1, *t2;
-
- TRACEPB("pd_post", printf("(%p)\n", t));
-
- if (t1 = t) {
- while (t2 = t1 -> t_link) {
- TRACEP("pd_post",
- printf("process %p: ", t1);
- pr_type(t1);
- );
- switch(t1 -> t_typtok) {
- case ARRAY_TYPE:
- if (t2 -> t_typtok == FUNCTION_TYPE) {
- t_error("declared: array of functions");
- }
- else {
- /* assign array size */
- t1 -> t_tsize =
- t1 -> t_tdim * t2 -> t_tsize;
-
- /* NOTE: scmods might be mixed--
- e.g. a volatile to propagate forward
- and a const to propagate backward */
-
- /* assign array scmods to element */
- t2 -> t_mclass |= t1 -> t_mclass;
-
- /* assign element scmods to array */
- /* quasi SHORTCUT */
- t1 -> t_mclass |= pd_post(t2);
-
- /* avoid continuing on thru chain */
-
- RETURN_INT("pd_post", t -> t_mclass & SC_MODS);
- }
- break;
-
- case FUNCTION_TYPE:
- switch(t2 -> t_typtok) {
- case STRUCT_TYPE:
- case UNION_TYPE:
- case ARRAY_TYPE:
- if (t1 -> t_typtok == FUNCTION_TYPE) {
- t_error("declared: function returning aggregate");
- }
- break;
- case FUNCTION_TYPE:
- t_error("declared: function returning function");
- break;
- }
- }
- t1 = t2;
- } /* end while */
-
- /* struct/union is terminal node, so check terminal */
- switch(t1 -> t_typtok) {
- case STRUCT_TYPE:
- case UNION_TYPE:
- TRACEP("pd_post", printf("structure: %p\n", t1));
- if (t1 -> t_mclass & SC_MODS) {
- /* go through each element node */
- t2 = t1; /* first t2 is the struct node;
- then it is successive elt nodes */
- while (t2 -> t_list) {
- /* replace the s/u element node */
- #if SC_STICKY == 0
- t2 -> t_list = node_dupl(
- (byte *) t2 -> t_list,
- sizeof(struct type_node));
- #endif
- t2 = t2 -> t_list; /* look at elt */
-
- /* replace part of elt list */
- t2 -> t_link = pd_p1(t2 -> t_link,
- t1 -> t_mclass);
- }
- }
- }
- RETURN_INT("pd_post", (t -> t_mclass & SC_MODS));
- }
- else {
- RETURN_INT("pd_post", 0);
- }
- }
-
- /*
- This is the substructure version of pd_post
-
- It doesn't bother with checks, since they are done already;
- its only job is to propagate SC_MODS in the forward direction
- from a struct/union, and it only traverses to the extent
- necessary to do this. This also prevents
- struct tag {
- struct tag *p;
- }
- from looping forever.
- */
- static struct type_node *
- pd_p1(register struct type_node *t, register int mods)
- {
- register struct type_node *t1, *t2, *t3;
-
- /* t is the attachment point */
-
- TRACEPB("pd_p1", printf("(%p, %d)\n", t, mods));
-
- if (t == NULL) {
- RETURN_PTR("pd_p1", t);
- }
- t1 = t;
-
- /* go through the list linkwise (only) */
- #if SC_STICKY == 0
- /* new attachment point */
- t = t1 = node_dupl( (byte *) t1, sizeof(struct type_node));
- #endif
- t1 -> t_mclass |= mods;
-
- while ((t2 = t1 -> t_link) && t1 -> t_typtok == ARRAY_TYPE) {
- /* assign scmods to array element */
- #if SC_STICKY == 0
- t2 = t1 -> t_link = node_dupl( (byte *) t2,
- sizeof(struct type_node));
- #endif
- t2 -> t_mclass |= t1 -> t_mclass;
- t1 = t2;
- } /* end while */
-
- switch(t1 -> t_typtok) {
- case STRUCT_TYPE:
- case UNION_TYPE:
- TRACEP("pd_p1", printf("structure: %p\n", t1));
- /* propagate const through element list */
- t2 = t1;
- while (t2 -> t_list) {
- /* replace the s/u element node */
- #if SC_STICKY == 0
- t2 -> t_list = (void *)
- node_dupl( (byte *) t2 -> t_list,
- sizeof(struct type_node));
- #endif
- t2 = t2 -> t_list; /* now look at the node */
-
- /* replace what is linked to the s/u element node */
- t2 -> t_link = pd_p1(t2 -> t_link,
- t1 -> t_mclass);
- }
- }
- RETURN_PTR("pd_p1", t);
- }
-
-
- /*
- Enter a symbol that has been fished out of a pd_tail onto
- some symbol table. Context information is used to determine
- whether duplicate entries are OK, and so on.
-
- A symbol table entry, guaranteed non-NULL, is returned.
- In FNDEF_SCOPE only, it may be that id -> st_type differs
- from type, and should replace type; the caller must deal with this.
-
- For FNDEF_SCOPE, the type_nodes are made in global memory. The
- st_nodes and symbols are made in local memory.
- */
- static struct st_node *
- pd_var(int sclass, struct type_node *type, char * symbol)
- {
- register struct st_node *id, *id1;
- register struct type_node *t;
- register int ttok;
-
- TRACEPB("pd_var", printf("(%d, %p, %s)\n", sclass, type, symbol));
-
- TRACEP("pd_var",
- pr_type(type);
- printf("class: ");
- pr_sclass(sclass);
- printf("\n");
- );
-
- #ifdef DEBUG
- if (type == NULL) {
- fatal("pd_var: internal: no type");
- }
- #endif /* DEBUG */
-
- ttok = type -> t_typtok;
- if (ttok == FUNCTION_TYPE) {
- if (sclass == STATICG_CLASS) {
- sclass = SCODE_CLASS;
- }
- else {
- sclass = CODE_CLASS;
- }
- TRACEP("pd_var", printf("classify as code\n"));
- }
- else {
- if (ttok == VOID_TYPE) {
- t_2error(symbol, " declared void");
- }
- else if (is_element(ttok)) {
- sclass = SUE_CLASS;
- TRACEP("pd_var", printf("classify as element\n"));
- }
- }
-
- /*
- WARNING: undefined structure can't be checked until decls are
- all done.
- */
-
- /* Look it up and enter it but in the current scope only. */
- id = rst_lookup(symbol);
- if (id == NULL) {
- /*
- id is not a duplicate symbol; set it up
- */
- id = rst_enter(symbol, type, sclass);
- id -> st_misc |= EXPLICIT_SYM;
- if (scope.s_scope == FNDEF_SCOPE) {
- t_2error("not in formal list: ", symbol);
- }
-
- /* Fix id's alias if it is a static declarator */
- /* NOTE: functions declared static are already CODE_CLASS */
- if (sclass == STATICL_CLASS) {
- id -> st_alias = str_salloc(pd_name());
- }
- }
- else if (scope.s_scope == FNDEF_SCOPE) {
- /*
- Formal scope duplicate messages.
- Formal scope reentry.
- */
- if (id -> st_misc & EXPLICIT_SYM) {
- t_2error("duplicate type specification of formal: "
- , symbol);
- }
- else {
- TRACEP("pd_var",
- printf("reenter formal %p\n", type));
- if (type != NULL) {
- switch(ttok) {
- case FUNCTION_TYPE:
- t_2error("formal declared a function: "
- , symbol);
- break;
-
- case UNION_TYPE:
- case ARRAY_TYPE:
- case STRUCT_TYPE:
- t_2error("formal declared an aggregate: "
- , symbol);
- break;
- }
- }
- /* Update the type inside the actual node. */
- pd_tcopy(type, id -> st_type);
- id -> st_sclass = sclass;
- id -> st_misc |= EXPLICIT_SYM;
- }
- }
- else {
- /*
- Non-formal scope duplicate messages
- */
- switch(ttok) {
- case SELEMENT_TYPE:
- case UELEMENT_TYPE:
- if (!pd_teq(type, id -> st_type))
- switch(id -> st_type -> t_typtok) {
- case SELEMENT_TYPE:
- case UELEMENT_TYPE:
- if (type -> t_tdim !=
- id -> st_type -> t_tdim) {
- t_2error("element offset conflict: ",
- symbol);
- }
- else {
- t_2error("element type conflict: ",
- symbol);
- }
- break;
- default:
- t_2error("not an element: ", symbol);
- }
- break;
-
- case FUNCTION_TYPE:
- if (!pd_teq(type, id -> st_type)) {
- t_2error("redeclaration of function: ",
- symbol);
- }
- break;
-
- default:
- t_2error("duplicate symbol: ", symbol);
- }
- }
- RETURN_PTR("pd_var", id);
- } /* end pd_var */
-
- /*
- Return a unique symbolic name for a (static) variable.
- */
- static char *
- pd_name(void)
- {
- static char buf[LONG_DIGITS+5];
- static unsigned long ssn = 1;
-
- TICK("pd_name");
-
- buf[0] = 'V';
- conul2sc(ssn, buf+1, 2);
-
- TRACEP("pd_name", printf("%d %s\n", str_len(buf), buf));
- ssn++;
- return &buf[0];
- }
-
- /*
- Parse initializers, and attach the initializer block(s) to
- the symbol id
-
- Initializer blocks come in several functions. The enumeration
- ..._DEC in enum.h lists these. Type zero is the array list, which
- contains n slots each of which holds a pointer and a numerical
- constant. It may in the end be preferable to instead make each
- slot a polymorphic longword with its own type. The pointer form
- will point to a loc_node that can hold a constant and a label, in
- order to accomodate initializers of the (label + offset) variety.
- According to K&R, that is the most complex form possible. Some
- users of realtime rom-based systems might not mind being able to
- pass through any parse tree that the assembler can handle, in which
- case the pointer might point to a general parse node instead of just
- a loc_node.
-
- The IBSSZB type is used for filler blocks in incomplete
- initializations. It is essentially meant to finesse the situation
- where a user declares int x[100000] = 0; and avoid attempting
- to produce in the compiler an array of 100000 double-longword
- structures! To keep things regular, this block is used for all
- fillers.
-
- The ISTRA type is for string arrays, in the sense of an array of
- char declared as a string. It is used for declarations like
- char a[6] = "hello"; and for implicit declarations in code.
-
- String pointer arrays declared as arrays of strings are "under
- development." Implicit string declarations in code, i.e. char *p;
- p = "hello"; create internal labels for the strings. These labels
- get entered into the symbol table, so that the loc_node can point
- back to a symbol in the customary fashion. (Entry into the table is
- primarily the most expedient way to get the symbol node created; the
- symbols are not looked up in the table.) The declaration
- char *a[] = {"first", "second", "third};
- is a little different again, in that it sets up THREE objects; namely,
- the internal label, the string itself, and the pointer variable. Each
- string declarator sets up two physical objects in storage, rather than
- the usual one.
- */
- static void
- pd_iniz(struct st_node *id)
- {
- TICK("pd_iniz");
- if (t_type == LCURLY_TOK) {
- get_token();
- id -> st_iniz = pd_par(id -> st_type, 1L);
- (void) needend(RCURLY_TOK);
- }
- else {
- id -> st_iniz = pd_par(id -> st_type, 1L);
- }
- /* supplementary error message */
- switch(t_type) {
- default:
- t_2error("declarator or semicolon expected at: ",
- ps_tok(t_type));
- case ID_TOK:
- case SEMICOLON_TOK:
- case STAR_TOK:
- case COMMA_TOK:
- case LPAREN_TOK:
- ;
- }
- }
-
- /*
- In effect we enter here from pd_iniz() with the outer braces
- stripped.
- */
- static struct iblock *
- pd_par(register struct type_node *t, unsigned long size)
- {
- register unsigned int j;
- register unsigned long i, c;
- register struct iblock *p, *q, *s;
- struct iblock base;
- struct st_node *id;
- int minus;
-
- TRACEPB("pd_par",
- printf("(%p, %lu)\n", t, size);
- pr_type(t));
-
- #ifdef DEBUG
- if (t == NULL) {
- t_error("internal: pd_par: no type");
- RETURN_PTR("pd_par", NULL);
- }
- #endif
-
- p = NULL;
-
- switch (t -> t_typtok) {
- case INT_TYPE:
- case POINTER_TYPE:
- /* get a decl block, which holds up to IDATA_SIZE long entries */
- p = q = new_iblock((size)? size : (unsigned long) IDATA_SIZE);
-
- q -> isize = (byte) t -> t_tsize;
- c = q -> idim;
-
- for (j = 0, i = 0; size == 0 || i < size; i++) {
-
- /* WARNING: must call pe_expr() if operators are found */
- /* probably should use character lookahead and call
- pe_expr if next is not ,;{} */
-
- if (minus = (t_type == MINUS_TOK)) {
- get_token();
- }
-
- /* this is forced to be an "if" statement since it
- needs in one case to break out of the "for" loop */
- if (t_type == INT_TOK || t_type == LONG_TOK ||
- t_type == STRING_TOK) {
- if (j >= IDATA_SIZE) {
- /* append another block */
- /* request remaining size */
- q -> ilink = new_iblock(
- (size)? size - i: (unsigned long) IDATA_SIZE);
- q = q -> ilink;
- q -> isize = (byte) t -> t_tsize;
- /* tot up actual initializers covered */
- c += q -> idim;
- j = 0;
- }
- if (t_type != STRING_TOK) {
- if (minus) {
- t_value = -t_value;
- }
- if (pe_oversize(t -> t_mclass, t_value) >= 2) {
- t_error("oversized initializer");
- }
- q -> idata[j++] . icn = t_value;
- }
- else {
- s = new_iblock(2L);
- s -> itype = ISTRS_DEC;
- s -> isize = 1;
- s -> idata[0] . ipt =
- (void *) str_lalloc(t_symbol);
- s -> idim = (unsigned long)
- str_val(s -> idata[0] . ipt);
- s -> idata[1] . ipt =
- (void *)str_lalloc(str_name());
- q -> idata[j++] . ipt = (char *) s;
- if (t -> t_tsize != 4) {
- t_error("string pointer truncated");
- TRACEP("pd_par", printf("t -> t_tsize = %ld\n", t -> t_tsize));
- }
- }
- get_token();
- }
- /* temporary code to handle address-of */
- else if (t_type == AND_TOK) {
- get_token();
- if (j >= IDATA_SIZE) {
- /* append another block */
- /* request remaining size */
- q -> ilink = new_iblock(
- (size)? size - i: (unsigned long) IDATA_SIZE);
- q = q -> ilink;
- q -> isize = (byte) t -> t_tsize;
- /* tot up actual initializers covered */
- c += q -> idim;
- j = 0;
- }
- if (t_type == ID_TOK) {
- if (id = ast_lookup(t_symbol)) {
- s = new_iblock(1L);
- s -> itype = ITAG_DEC;
- s -> idata[0].ipt =
- id -> st_alias;
- q -> idata[j++] . ipt =
- (char *) s;
- }
- else {
- t_2error("undefined symbol: ",
- t_symbol);
- j++;
- }
- get_token();
- }
- else {
- t_2error("cannot handle declaration syntax at: ",
- ps_tok(t_type));
- }
- }
- else {
- break;
- }
-
- if (t_type == COMMA_TOK) {
- get_token();
- }
- else {
- break;
- }
- }
- /* append a bsszb block to fill out size */
- if (size) {
- if (size > c) {
- q -> ilink = new_iblock(0L);
- q = q -> ilink;
- q -> idim = (size - c) * t -> t_tsize;
- q -> itype = IBSSZB_DEC;
- }
- }
- else {
- q -> idim = (unsigned long)j;
- }
-
- TRACEP("pd_par",
- q = p;
- while(q) {
- pr_iblock(q);
- q = q -> ilink;
- }
- );
- break;
-
- case ARRAY_TYPE:
- q = &base;
- base . ilink = NULL;
-
- /* get chain of blocks */
- TRACEP("pd_par", array: pr_type(t -> t_link));
- if (t_type == STRING_TOK &&
- t -> t_link -> t_typtok == INT_TYPE &&
- t -> t_link -> t_tsize == 1) {
- /* generate special string block */
- p = new_iblock(1L);
- p -> itype = ISTRA_DEC;
- p -> isize = 1;
- p -> idata[0] . ipt = (void *) str_lalloc(t_symbol);
- i = (unsigned long) str_val(p->idata[0].ipt);
- if (t -> t_tdim && i > t -> t_tdim) {
- i = t -> t_tdim;
- ((char *) p -> idata [0] . ipt) [i] = 0;
- t_warning("string initializer truncated");
- }
- p -> idim = i;
- TRACEP("pd_par", pr_iblock(p));
- if (i < t -> t_tdim) {
- q = new_iblock(0L);
- p -> ilink = q;
- q -> itype = IBSSZB_DEC;
- q -> idim = t -> t_tdim - i;
- TRACEP("pd_par", pr_iblock(q));
- }
- get_token();
- }
- else if (t_type == LCURLY_TOK) {
- /* get a braced set of initializers */
- if (t -> t_tdim == 0) {
- t_error("missing dimension, initialized array");
- }
- for (i = 0; i < t -> t_tdim; ) {
- TRACEP("pd_par", printf("array: i = %lu\n", i));
- get_token();
- q -> ilink = pd_par(t -> t_link, 1L);
- i++;
-
- /* seek to end of chain */
- while (q -> ilink) {
- q = q -> ilink;
- }
-
- /* eat a right brace */
- if (!needend(RCURLY_TOK)) {
- break;
- }
- /* and a comma */
- if (t_type != COMMA_TOK) {
- break;
- }
- get_token();
- if (t_type != LCURLY_TOK) {
- break;
- }
- }
- /* append a bsszb block to fill out size */
- if (i < t -> t_tdim) {
- q -> ilink = new_iblock(0L);
- q -> ilink -> itype = IBSSZB_DEC;
- q = q -> ilink;
- q -> idim = (t -> t_tdim - i) *
- t -> t_link -> t_tsize;
- TRACEP("pd_par", pr_iblock(q));
- }
- /* t is no good here */
- p = base.ilink;
- }
- else {
- /* get an open list of initializers */
- if (t -> t_tdim == 0) switch (t -> t_link -> t_typtok){
- case INT_TYPE:
- case POINTER_TYPE:
- break;
- default:
- t_error("missing dimension, initialized array");
- }
- TRACEP("pd_par", printf("open list\n"));
- p = pd_par(t -> t_link, size * t -> t_tdim);
- }
- break;
-
- case STRUCT_TYPE:
- /* do this the simplest way */
- q = &base;
- base . ilink = NULL;
- while (t = t -> t_list) {
- switch(t -> t_link -> t_typtok) {
- case STRUCT_TYPE:
- case ARRAY_TYPE:
- if (t_type == LCURLY_TOK) {
- get_token();
- q -> ilink = pd_par(t -> t_link, 1L);
- q = q -> ilink;
- (void) needend(RCURLY_TOK);
- break;
- }
- /* FALLTHROUGH */
- default:
- q -> ilink = pd_par(t -> t_link, 1L);
- q = q -> ilink;
- }
- }
- p = base.ilink;
- break;
-
- case FUNCTION_TYPE:
- t_error("cannot initialize a function");
- break;
-
- default:
- t_error("cannot initialize object of this type");
- TRACEP("pd_par", pr_type(t); printf("\n"));
- }
- /* CAUTION: size and t are no good here */
- RETURN_PTR("pd_par", p);
- }
-